#pragma once

#include <AVUIUIPropertyMetadata.h>

// [REVIEWED 08/02/2008 -- GHERMANN]

namespace AVUI {

class FrameworkPropertyMetadata : public UIPropertyMetadata
{
public:
    DECLARE_ELEMENT(FrameworkPropertyMetadata, UIPropertyMetadata);

#pragma region Public Methods

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkPropertyMetadata" /> class. </summary>
    FrameworkPropertyMetadata() 
    { Initialize(); }

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkPropertyMetadata" /> class with the specified default value. </summary>
    /// <param name="defaultValue">The default value of the dependency property, usually provided as a value of a specific type.</param>
    /// <exception cref="T:System.ArgumentException">
    /// <paramref name="defaultValue" /> is set to <see cref="F:System.Windows.DependencyProperty.UnsetValue" />; see Remarks.</exception>
    FrameworkPropertyMetadata(Object* pDefaultValue) : UIPropertyMetadata(pDefaultValue) 
    { Initialize(); }

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkPropertyMetadata" /> class with the specified <see cref="T:System.Windows.PropertyChangedCallback" /> callback.</summary>
    /// <param name="propertyChangedCallback">A reference to a handler implementation that the property system will call whenever the effective value of the property changes.</param>
    FrameworkPropertyMetadata(PropertyChangedCallback propertyChangedCallback) : UIPropertyMetadata(propertyChangedCallback) 
    { Initialize(); }

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkPropertyMetadata" /> class with the provided default value and framework-level metadata options. </summary>
    /// <param name="defaultValue">The default value of the dependency property, usually provided as a value of a specific type.</param>
    /// <param name="flags">The metadata option flags (a combination of <see cref="T:System.Windows.FrameworkPropertyMetadataOptions" /> values). These options specify characteristics of the dependency property that interact with systems such as layout or data binding.</param>
    /// <exception cref="T:System.ArgumentException">
    /// <paramref name="defaultValue" /> is set to <see cref="F:System.Windows.DependencyProperty.UnsetValue" />; see Remarks.</exception>
    FrameworkPropertyMetadata(Object* pDefaultValue, unsigned int flags) : UIPropertyMetadata(pDefaultValue) 
    { TranslateFlags(flags); }

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkPropertyMetadata" /> class with the provided default value and specified <see cref="T:System.Windows.PropertyChangedCallback" /> callback. </summary>
    /// <param name="defaultValue">The default value of the dependency property, usually provided as a value of a specific type.</param>
    /// <param name="propertyChangedCallback">A reference to a handler implementation that the property system will call whenever the effective value of the property changes.</param>
    /// <exception cref="T:System.ArgumentException">
    /// <paramref name="defaultValue" /> is set to <see cref="F:System.Windows.DependencyProperty.UnsetValue" />; see Remarks.</exception>
    FrameworkPropertyMetadata(Object* pDefaultValue, PropertyChangedCallback propertyChangedCallback) : UIPropertyMetadata(pDefaultValue, propertyChangedCallback) 
    { Initialize(); }

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkPropertyMetadata" /> class with the specified callbacks. </summary>
    /// <param name="propertyChangedCallback">A reference to a handler implementation that the property system will call whenever the effective value of the property changes.</param>
    /// <param name="coerceValueCallback">A reference to a handler implementation will be called whenever the property system calls <see cref="M:System.Windows.DependencyObject.CoerceValue(System.Windows.DependencyProperty)" /> for this dependency property.</param>
    FrameworkPropertyMetadata(PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback) : UIPropertyMetadata(propertyChangedCallback) 
    { Initialize(); set_CoerceValueCallback(coerceValueCallback); }

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkPropertyMetadata" /> class with the provided default value and framework metadata options, and specified <see cref="T:System.Windows.PropertyChangedCallback" /> callback. </summary>
    /// <param name="defaultValue">The default value of the dependency property, usually provided as a value of a specific type.</param>
    /// <param name="flags">The metadata option flags (a combination of <see cref="T:System.Windows.FrameworkPropertyMetadataOptions" /> values). These options specify characteristics of the dependency property that interact with systems such as layout or data binding.</param>
    /// <param name="propertyChangedCallback">A reference to a handler implementation that the property system will call whenever the effective value of the property changes.</param>
    /// <exception cref="T:System.ArgumentException">
    /// <paramref name="defaultValue" /> is set to <see cref="F:System.Windows.DependencyProperty.UnsetValue" />; see Remarks.</exception>
    FrameworkPropertyMetadata(Object* pDefaultValue, unsigned int flags, PropertyChangedCallback propertyChangedCallback) : UIPropertyMetadata(pDefaultValue, propertyChangedCallback) 
    { TranslateFlags(flags); }

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkPropertyMetadata" /> class with the provided default value and specified callbacks.</summary>
    /// <param name="defaultValue">The default value of the dependency property, usually provided as a specific type.</param>
    /// <param name="propertyChangedCallback">A reference to a handler implementation that the property system will call whenever the effective value of the property changes.</param>
    /// <param name="coerceValueCallback">A reference to a handler implementation that will be called whenever the property system calls <see cref="M:System.Windows.DependencyObject.CoerceValue(System.Windows.DependencyProperty)" /> for this dependency property.</param>
    /// <exception cref="T:System.ArgumentException">
    /// <paramref name="defaultValue" /> is set to <see cref="F:System.Windows.DependencyProperty.UnsetValue" />; see Remarks.</exception>
    FrameworkPropertyMetadata(Object* pDefaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback) : UIPropertyMetadata(pDefaultValue, propertyChangedCallback, coerceValueCallback) 
    { Initialize(); }

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkPropertyMetadata" /> class with the provided default value and framework metadata options, and specified callbacks. </summary>
    /// <param name="defaultValue">The default value of the dependency property, usually provided as a specific type.</param>
    /// <param name="flags">The metadata option flags (a combination of <see cref="T:System.Windows.FrameworkPropertyMetadataOptions" /> values). These options specify characteristics of the dependency property that interact with systems such as layout or data binding.</param>
    /// <param name="propertyChangedCallback">A reference to a handler implementation that the property system will call whenever the effective value of the property changes.</param>
    /// <param name="coerceValueCallback">A reference to a handler implementation that will be called whenever the property system calls <see cref="M:System.Windows.DependencyObject.CoerceValue(System.Windows.DependencyProperty)" /> against this property.</param>
    /// <exception cref="T:System.ArgumentException">
    /// <paramref name="defaultValue" /> is set to <see cref="F:System.Windows.DependencyProperty.UnsetValue" />; see Remarks.</exception>
    FrameworkPropertyMetadata(Object* pDefaultValue, unsigned int flags, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback) : UIPropertyMetadata(pDefaultValue, propertyChangedCallback, coerceValueCallback) 
    { TranslateFlags(flags); }

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkPropertyMetadata" /> class with the provided default value and framework metadata options, specified callbacks, and a Boolean that can be used to prevent animation of the property.</summary>
    /// <param name="defaultValue">The default value of the dependency property, usually provided as a specific type.</param>
    /// <param name="flags">The metadata option flags (a combination of <see cref="T:System.Windows.FrameworkPropertyMetadataOptions" /> values). These options specify characteristics of the dependency property that interact with systems such as layout or data binding.</param>
    /// <param name="propertyChangedCallback">A reference to a handler implementation that the property system will call whenever the effective value of the property changes.</param>
    /// <param name="coerceValueCallback">A reference to a handler implementation that will be called whenever the property system calls <see cref="M:System.Windows.DependencyObject.CoerceValue(System.Windows.DependencyProperty)" /> on this dependency property.</param>
    /// <param name="isAnimationProhibited">true to prevent the property system from animating the property that this metadata is applied to. Such properties will raise a run-time exception originating from the property system if animations of them are attempted. false to permit animating the property. The default is false.</param>
    /// <exception cref="T:System.ArgumentException">
    /// <paramref name="defaultValue" /> is set to <see cref="F:System.Windows.DependencyProperty.UnsetValue" />; see Remarks.</exception>
    FrameworkPropertyMetadata(Object* pDefaultValue, unsigned int flags, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback, bool isAnimationProhibited) : UIPropertyMetadata(pDefaultValue, propertyChangedCallback, coerceValueCallback, isAnimationProhibited) 
    { TranslateFlags(flags); }

    /// <summary>Initializes a new instance of the <see cref="T:System.Windows.FrameworkPropertyMetadata" /> class with the provided default value and framework metadata options, specified callbacks, a Boolean that can be used to prevent animation of the property, and a data-binding update trigger default.</summary>
    /// <param name="defaultValue">The default value of the dependency property, usually provided as a specific type.</param>
    /// <param name="flags">The metadata option flags (a combination of <see cref="T:System.Windows.FrameworkPropertyMetadataOptions" /> values). These options specify characteristics of the dependency property that interact with systems such as layout or data binding.</param>
    /// <param name="propertyChangedCallback">A reference to a handler implementation that the property system will call whenever the effective value of the property changes.</param>
    /// <param name="coerceValueCallback">A reference to a handler implementation that will be called whenever the property system calls <see cref="M:System.Windows.DependencyObject.CoerceValue(System.Windows.DependencyProperty)" /> against this property.</param>
    /// <param name="isAnimationProhibited">true to prevent the property system from animating the property that this metadata is applied to. Such properties will raise a run-time exception originating from the property system if animations of them are attempted. The default is false.</param>
    /// <param name="defaultUpdateSourceTrigger">The <see cref="T:System.Windows.Data.UpdateSourceTrigger" /> to use when bindings for this property are applied that have their <see cref="T:System.Windows.Data.UpdateSourceTrigger" /> set to <see cref="F:System.Windows.Data.UpdateSourceTrigger.Default" />.</param>
    /// <exception cref="T:System.ArgumentException">
    /// <paramref name="defaultValue" /> is set to <see cref="F:System.Windows.DependencyProperty.UnsetValue" />; see Remarks.</exception>
    FrameworkPropertyMetadata(Object* pDefaultValue, unsigned int flags, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback, bool isAnimationProhibited, UpdateSourceTrigger::Enum updateSourceTrigger);

#pragma endregion Public Methods
 
#pragma region Public Properties

    /// <summary> Gets or sets a value that indicates whether a dependency property potentially affects the arrange pass during layout engine operations. </summary>
    /// <returns>true if the dependency property on which this metadata exists potentially affects the arrange pass; otherwise, false. The default is false.</returns>
    /// <exception cref="T:System.InvalidOperationException">The metadata has already been applied to a dependency property operation, so that metadata is sealed and properties of the metadata cannot be set.</exception>
    bool get_AffectsArrange() { return ReadFlag(PropertyMetadata::MetadataFlags::FW_AffectsArrangeID); }
    void set_AffectsArrange(bool value);

    /// <summary> Gets or sets a value that indicates whether a dependency property potentially affects the measure pass during layout engine operations. </summary>
    /// <returns>true if the dependency property on which this metadata exists potentially affects the measure pass; otherwise, false. The default is false.</returns>
    /// <exception cref="T:System.InvalidOperationException">The metadata has already been applied to a dependency property operation, so that metadata is sealed and properties of the metadata cannot be set.</exception>
    bool get_AffectsMeasure() { return ReadFlag(PropertyMetadata::MetadataFlags::FW_AffectsMeasureID); }
    void set_AffectsMeasure(bool value);

    /// <summary> Gets or sets a value that indicates whether a dependency property potentially affects the arrange pass of its parent element's layout during layout engine operations. </summary>
    /// <returns>true if the dependency property on which this metadata exists potentially affects the arrange pass specifically on its parent element; otherwise, false. The default is false.</returns>
    /// <exception cref="T:System.InvalidOperationException">The metadata has already been applied to a dependency property operation, so that metadata is sealed and properties of the metadata cannot be set.</exception>
    bool get_AffectsParentArrange() { return ReadFlag(PropertyMetadata::MetadataFlags::FW_AffectsParentArrangeID); }
    void set_AffectsParentArrange(bool value);

    /// <summary> Gets or sets a value that indicates whether a dependency property potentially affects the measure pass of its parent element's layout during layout engine operations. </summary>
    /// <returns>true if the dependency property on which this metadata exists potentially affects the measure pass specifically on its parent element; otherwise, false.The default is false. </returns>
    /// <exception cref="T:System.InvalidOperationException">The metadata has already been applied to a dependency property operation, so that metadata is sealed and properties of the metadata cannot be set.</exception>
    bool get_AffectsParentMeasure() { return ReadFlag(PropertyMetadata::MetadataFlags::FW_AffectsParentMeasureID); }
    void set_AffectsParentMeasure(bool value);

    /// <summary>Gets or sets a value that indicates whether a dependency property potentially affects the general layout in some way that does not specifically influence arrangement or measurement, but would require a redraw. </summary>
    /// <returns>true if the dependency property on which this metadata exists affects rendering; otherwise, false. The default is false.</returns>
    /// <exception cref="T:System.InvalidOperationException">The metadata has already been applied to a dependency property operation, so that metadata is sealed and properties of the metadata cannot be set.</exception>
    bool get_AffectsRender() { return ReadFlag(PropertyMetadata::MetadataFlags::FW_AffectsRenderID); }
    void set_AffectsRender(bool value);

    /// <summary> Gets or sets a value that indicates whether the property binds two-way by default. </summary>
    /// <returns>true if the dependency property on which this metadata exists binds two-way by default; otherwise, false. The default is false.</returns>
    /// <exception cref="T:System.InvalidOperationException">The metadata has already been applied to a dependency property operation, so that metadata is sealed and properties of the metadata cannot be set.</exception>
    bool get_BindsTwoWayByDefault() { return ReadFlag(PropertyMetadata::MetadataFlags::FW_BindsTwoWayByDefaultID); }
    void set_BindsTwoWayByDefault(bool value);

    /// <summary>Gets or sets the default for <see cref="T:System.Windows.Data.UpdateSourceTrigger" /> to use when bindings for the property with this metadata are applied, which have their <see cref="T:System.Windows.Data.UpdateSourceTrigger" /> set to <see cref="F:System.Windows.Data.UpdateSourceTrigger.Default" />.</summary>
    /// <returns>A value of the enumeration, other than <see cref="F:System.Windows.Data.UpdateSourceTrigger.Default" />.</returns>
    /// <exception cref="T:System.ArgumentException">This property is set to <see cref="F:System.Windows.Data.UpdateSourceTrigger.Default" />; the value you set is supposed to become the default when requested by bindings.</exception>
    /// <exception cref="T:System.InvalidOperationException">The metadata has already been applied to a dependency property operation, so that metadata is sealed and properties of the metadata cannot be set.</exception>
    UpdateSourceTrigger::Enum get_DefaultUpdateSourceTrigger();
    void set_DefaultUpdateSourceTrigger(UpdateSourceTrigger::Enum value);

    /// <summary> Gets or sets a value that indicates whether the value of the dependency property is inheritable. </summary>
    /// <returns>true if the property value is inheritable; otherwise, false. The default is false.</returns>
    /// <exception cref="T:System.InvalidOperationException">The metadata has already been applied to a dependency property operation, so that metadata is sealed and properties of the metadata cannot be set.</exception>
    bool get_Inherits() { return get_IsInherited(); }
    void set_Inherits(bool value);

    /// <summary> Gets a value that indicates whether data binding is supported for the dependency property. </summary>
    /// <returns>true if data binding is supported on the dependency property to which this metadata applies; otherwise, false. The default is true.</returns>
    bool get_IsDataBindingAllowed() { return !ReadFlag(PropertyMetadata::MetadataFlags::FW_IsNotDataBindableID) && !get_ReadOnly(); }

    /// <summary> Gets or sets a value that indicates whether the dependency property supports data binding. </summary>
    /// <returns>true if the property does not support data binding; otherwise, false. The default is false.</returns>
    /// <exception cref="T:System.InvalidOperationException">The metadata has already been applied to a dependency property operation, so that metadata is sealed and properties of the metadata cannot be set.</exception>
    bool get_IsNotDataBindable() { return ReadFlag(PropertyMetadata::MetadataFlags::FW_IsNotDataBindableID); }
    void set_IsNotDataBindable(bool value);

    /// <summary> Gets or sets a value that indicates whether this property contains journaling information that applications can or should store as part of a journaling implementation. </summary>
    /// <returns>true if journaling should be performed on the dependency property that this metadata is applied to; otherwise, false. The default is false.</returns>
    /// <exception cref="T:System.InvalidOperationException">The metadata has already been applied to a dependency property operation, so that metadata is sealed and properties of the metadata cannot be set.</exception>
	bool get_Journal() { return ReadFlag(PropertyMetadata::MetadataFlags::FW_ShouldBeJournaledID); }
    void set_Journal(bool value);

    /// <summary>Gets or sets a value that indicates whether the property value inheritance evaluation should span across certain content boundaries in the logical tree of elements. </summary>
    /// <returns>true if the property value inheritance should span across certain content boundaries; otherwise, false. The default is false.</returns>
    /// <exception cref="T:System.InvalidOperationException">The metadata has already been applied to a dependency property operation, so that metadata is sealed and properties of the metadata cannot be set.</exception>
    bool get_OverridesInheritanceBehavior() { return ReadFlag(PropertyMetadata::MetadataFlags::FW_OverridesInheritanceBehaviorID); }
    void set_OverridesInheritanceBehavior(bool value);

    /// <summary>Gets or sets a value that indicates whether sub-properties of the dependency property do not affect the rendering of the containing object. </summary>
    /// <returns>true if changes to sub-property values do not affect rendering if changed; otherwise, false. The default is false.</returns>
    /// <exception cref="T:System.InvalidOperationException">The metadata has already been applied to a dependency property operation, so that metadata is sealed and properties of the metadata cannot be set.</exception>
    bool get_SubPropertiesDoNotAffectRender() { return ReadFlag(PropertyMetadata::MetadataFlags::FW_SubPropertiesDoNotAffectRenderID); }
    void set_SubPropertiesDoNotAffectRender(bool value);

#pragma endregion Public Properties
 
protected:

#pragma region Protected Methods

    /// <summary>Enables a merge of the source metadata with base metadata. </summary>
    /// <returns />
    /// <param name="baseMetadata">The base metadata to merge.</param>
    /// <param name="dp">The dependency property this metadata is being applied to.</param>
    void Merge(PropertyMetadata* pBaseMetadata, DependencyProperty* pDP) AVUI_OVERRIDE;

    /// <summary>Called when this metadata has been applied to a property, which indicates that the metadata is being sealed. </summary>
    /// <returns />
    /// <param name="dp">The dependency property to which the metadata has been applied.</param>
    /// <param name="targetType">The type associated with this metadata if this is type-specific metadata. If this is default metadata, this value can be null.</param>
    void OnApply(DependencyProperty* pDP, const Type* pTargetType) AVUI_OVERRIDE;

#pragma endregion Protected Methods

public:

#pragma region Internal Methods

    TRefCountedPtr<PropertyMetadata> CreateInstance() AVUI_OVERRIDE
    {
        return (PropertyMetadata*)object_allocate<FrameworkPropertyMetadata>();
    }

    bool IsModified(PropertyMetadata::MetadataFlags::Enum flag) { return ReadFlag(flag); }
    void SetModified(PropertyMetadata::MetadataFlags::Enum flag) { WriteFlag(flag, true); } 

#pragma endregion Internal Methods

private:

#pragma region Private Methods

    void Initialize();
    static bool IsFlagSet(FrameworkPropertyMetadataOptions::Enum flag, unsigned int flags) { return (flags & flag) != 0; }
    void TranslateFlags(unsigned int flags);

#pragma endregion Private Methods

#pragma region Private Properties

    bool get_ReadOnly() { return ReadFlag(PropertyMetadata::MetadataFlags::FW_ReadOnlyID); }
    void set_ReadOnly(bool value);

#pragma endregion Private Properties

};

class ReadOnlyFrameworkPropertyMetadata : public FrameworkPropertyMetadata
{
public:
#pragma region Internal API

    DECLARE_ELEMENT(ReadOnlyFrameworkPropertyMetadata, FrameworkPropertyMetadata);

    ReadOnlyFrameworkPropertyMetadata(Object* pDefaultValue, GetReadOnlyValueCallback getValueCallback) : FrameworkPropertyMetadata(pDefaultValue), m_getValueCallback(getValueCallback) { }

    virtual GetReadOnlyValueCallback get_GetReadOnlyValueCallback() AVUI_OVERRIDE { return m_getValueCallback; }

#pragma endregion Internal API

private:

#pragma region Private Fields

    GetReadOnlyValueCallback m_getValueCallback;

#pragma endregion Private Fields
};

}; // namespace AVUI



